﻿using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using l1cs_cl.client.utils;

namespace l1cs_cl.client
{
    class PlayerThread
    {
        private static PlayerThread _instance;

        //List<byte[]> readList;

        public static Encoding enc = Encoding.GetEncoding( "SJIS" );

        private static TcpClient tcp;

        private static NetworkStream stream;

        private PacketHandler _handler = new PacketHandler();

        private PlayerThread()
        {
            //readList = new List<byte[]>();
        }

        public static PlayerThread Instance
        {
            get
            {
                if ( _instance == null )
                    _instance = new PlayerThread();
                return _instance;
            }
        }

        public bool connect( String server )
        {
            //サーバーのホスト名とポート番号
            String host = server;
            int port = 2000;

            //TcpClientを作成し、サーバーと接続する
            try
            {
                tcp = new TcpClient( host, port );
            }
            catch ( SocketException )
            {
                return false;
            }

            //NetworkStreamを取得する
            stream = tcp.GetStream();
            return true;
        }

        public void disconnect()
        {
            if ( stream != null )
            {
                stream.Close();
            }
            if ( tcp != null )
            {
                tcp.Close();
            }
        }

        public void readThread()
        {
            byte[] data = null;
            while ( true )
            {
                try
                {
                    data = readPacket();
                    _handler.handlePacket( data );
                    //lock ( readList )
                    //{
                    //    readList.Add( data );
                    //}
                }
                catch ( Exception )
                {
                    Thread.Sleep( 100 );
                }
            }
        }

        //public static byte[] getPacket( int opcode )
        //{
        //    lock ( _instance.readList )
        //    {
        //        int i = 0;
        //        foreach ( byte[] data in _instance.readList )
        //        {
        //            if ( opcode == data[0] )
        //            {
        //                _instance.readList.RemoveAt( i );
        //                return data;
        //            }
        //            i++;
        //        }
        //        return null;
        //    }
        //}

        // 例外発生時にNULLで返す
        public static byte[] readPacketNoTry()
        {
            try
            {
                return _instance.readPacket();
            }
            catch ( Exception )
            {
                return null;
            }

        }

        public byte[] readPacket()
        {
            byte[] getData = new byte[1];
            try
            {
                stream.Read( getData, 0, getData.Length );
                int hiByte = Convert.ToInt32( getData[0] );// _in.read();
                stream.Read( getData, 0, getData.Length );
                int loByte = Convert.ToInt32( getData[0] );//_in.read();
                if ( loByte < 0 )
                {
                    throw new Exception();
                }
                int dataLength = ( loByte * 256 + hiByte ) - 2;

                List<byte> data = new List<byte>();//new byte[dataLength];

                int readSize = 0;

                //for ( int i = 0; i != -1 && readSize < dataLength; readSize += i )
                for ( int i = 0; i < dataLength; i++ )
                {
                    //i = _in.Read( data, readSize, dataLength - readSize );
                    stream.Read( getData, 0, getData.Length );
                    data.Add( getData[0] );
                    readSize++;
                }

                if ( readSize != dataLength )
                {
                    throw new ApplicationException( "読み込みサイズが異常です。" );
                }
#if DEBUG
                String opcode;
                sOpCode.TryGetValue( data[0], out opcode );
                String consoleStr = String.Format( "[受信データ<<<< Opcode={0} {1}]\n{2}",
                    data[0], opcode, ByteArrayUtil.dumpToString( data.ToArray() ) );
                Console.WriteLine( consoleStr );
#endif
                return data.ToArray();
            }
            catch ( Exception ex )
            {
                throw;
            }
        }

        public static void SendPackets( byte[] data )
        {
            byte[] senddata = new byte[data.Length + 2];
            int j = data.Length + 2;
            senddata[0] = (byte)( j & 0xff );
            senddata[1] = (byte)( j >> 8 & 0xff );
            System.Array.Copy( data, 0, senddata, 2, data.Length );
#if DEBUG
            String opcode;
            cOpCode.TryGetValue( data[0], out opcode );
            String consoleStr = String.Format("[送信データ>>>> Opcode={0} {1}]\n{2}",
                data[0], opcode, ByteArrayUtil.dumpToString( senddata ) );
            Console.WriteLine( consoleStr );
#endif
            stream.Write( senddata, 0, senddata.Length );
            stream.Flush();
        }

        // ここから先デバッグ用
        static Dictionary<int, String> cOpCode = new Dictionary<int, string>();
        static Dictionary<int, String> sOpCode = new Dictionary<int, string>();
        static PlayerThread()
        {
            cOpCode[0] = "C_OPCODE_BOOKMARK";
            cOpCode[3] = "C_OPCODE_FIGHT";
            cOpCode[4] = "C_OPCODE_KEEPALIVE";
            cOpCode[5] = "C_OPCODE_ATTACK";
            cOpCode[6] = "C_OPCODE_CHANGEHEADING";
            cOpCode[7] = "C_OPCODE_PICKUPITEM";
            cOpCode[8] = "C_OPCODE_SHOP";
            cOpCode[10] = "C_OPCODE_DELBUDDY";
            cOpCode[11] = "C_OPCODE_LEAVEPARTY";
            cOpCode[14] = "C_OPCODE_CHARACTERCONFIG";
            cOpCode[15] = "C_OPCODE_MOVECHAR";
            cOpCode[16] = "C_OPCODE_CHANGECHAR";
            cOpCode[17] = "C_OPCODE_PRIVATESHOPLIST";
            cOpCode[18] = "C_OPCODE_CHAT";
            cOpCode[19] = "C_OPCODE_BOARDREAD";
            cOpCode[20] = "C_OPCODE_TRADEADDITEM";
            cOpCode[22] = "C_OPCODE_PROPOSE";
            cOpCode[23] = "C_OPCODE_HIRESOLDIER";
            cOpCode[24] = "C_OPCODE_BOARD";
            cOpCode[25] = "C_OPCODE_LOGINTOSERVEROK";
            cOpCode[26] = "C_OPCODE_ENTERPORTAL";
            cOpCode[27] = "C_OPCODE_LEAVECLANE";
            cOpCode[29] = "C_OPCODE_CALL";
            cOpCode[30] = "C_OPCODE_TRADE";
            cOpCode[31] = "C_OPCODE_SKILLBUYOK";
            cOpCode[32] = "C_OPCODE_DELEXCLUDE";
            cOpCode[33] = "C_OPCODE_SHIP";
            cOpCode[34] = "C_OPCODE_CLIENTVERSION";
            cOpCode[38] = "C_OPCODE_EXTCOMMAND";
            cOpCode[41] = "C_OPCODE_TRADEADDCANCEL";
            cOpCode[42] = "C_OPCODE_DRAWAL";
            cOpCode[46] = "C_OPCODE_COMMONCLICK";
            cOpCode[47] = "C_OPCODE_SELECTTARGET";
            cOpCode[50] = "C_OPCODE_NEWCHAR";
            cOpCode[51] = "C_OPCODE_FIX_WEAPON_LIST";
            cOpCode[52] = "C_OPCODE_DROPITEM";
            cOpCode[54] = "C_OPCODE_DELETECHAR";
            cOpCode[56] = "C_OPCODE_ADDBUDDY";
            cOpCode[57] = "C_OPCODE_WHO";
            cOpCode[60] = "C_OPCODE_BOARDDELETE";
            cOpCode[61] = "C_OPCODE_TRADEADDOK";
            cOpCode[62] = "C_OPCODE_CREATECLAN";
            cOpCode[63] = "C_OPCODE_ATTR";
            cOpCode[64] = "C_OPCODE_ARROWATTACK";
            cOpCode[65] = "C_OPCODE_NPCACTION";
            cOpCode[66] = "C_OPCODE_TITLE";
            cOpCode[68] = "C_OPCODE_DEPOSIT";
            cOpCode[69] = "C_OPCODE_DELETEINVENTORYITEM";
            cOpCode[70] = "C_OPCODE_CHECKPK";
            cOpCode[72] = "C_OPCODE_BANPARTY";
            cOpCode[73] = "C_OPCODE_CLAN";
            cOpCode[75] = "C_OPCODE_DOOR";
            cOpCode[76] = "C_OPCODE_PLEDGE";
            cOpCode[77] = "C_OPCODE_PARTY";
            cOpCode[78] = "C_OPCODE_RANK";
            cOpCode[79] = "C_OPCODE_TELEPORT";
            cOpCode[80] = "C_OPCODE_CHARRESET";
            cOpCode[82] = "C_OPCODE_RESTART";
            cOpCode[83] = "C_OPCODE_PETMENU";
            cOpCode[84] = "C_OPCODE_BOARDWRITE";
            cOpCode[85] = "C_OPCODE_GIVEITEM";
            cOpCode[87] = "C_OPCODE_BOARDBACK";
            cOpCode[89] = "C_OPCODE_LOGINTOSERVER";
            cOpCode[92] = "C_OPCODE_CHATWHISPER";
            cOpCode[93] = "C_OPCODE_SKILLBUY";
            cOpCode[94] = "C_OPCODE_JOINCLAN";
            cOpCode[95] = "C_OPCODE_RETURNTOLOGIN";
            cOpCode[98] = "C_OPCODE_CHANGEWARTIME";
            cOpCode[101] = "C_OPCODE_WAR";
            cOpCode[103] = "C_OPCODE_BANCLAN";
            cOpCode[104] = "C_OPCODE_RESULT";
            cOpCode[109] = "C_OPCODE_BUDDYLIST";
            cOpCode[110] = "C_OPCODE_TAXRATE";
            cOpCode[111] = "C_OPCODE_USEPETITEM";
            cOpCode[112] = "C_OPCODE_SELECTLIST";
            cOpCode[113] = "C_OPCODE_LOGINPACKET";
            cOpCode[114] = "C_OPCODE_QUITGAME";
            cOpCode[115] = "C_OPCODE_CHATGLOBAL";
            cOpCode[116] = "C_OPCODE_EXCLUDE";
            cOpCode[118] = "C_OPCODE_NPCTALK";
            cOpCode[119] = "C_OPCODE_USEITEM";
            cOpCode[120] = "C_OPCODE_EMBLEM";
            cOpCode[121] = "C_OPCODE_EXIT_GHOST";
            cOpCode[124] = "C_OPCODE_AMOUNT";
            cOpCode[125] = "C_OPCODE_FISHCLICK";
            cOpCode[127] = "C_OPCODE_MAIL";
            cOpCode[128] = "C_OPCODE_BOOKMARKDELETE";
            cOpCode[129] = "C_OPCODE_USESKILL";
            cOpCode[130] = "C_OPCODE_CREATEPARTY";
            cOpCode[131] = "C_OPCODE_CAHTPARTY";
            sOpCode[0] = "S_OPCODE_REMOVE_OBJECT";
            sOpCode[1] = "S_OPCODE_CHARPACK ";
            sOpCode[1] += "S_OPCODE_DROPITEM";
            sOpCode[2] = "S_OPCODE_POLY";
            sOpCode[3] = "S_OPCODE_SYSMSG ";
            sOpCode[3] += "S_OPCODE_GLOBALCHAT";
            sOpCode[6] = "S_OPCODE_DOACTIONGFX";
            sOpCode[7] = "S_OPCODE_EMBLEM";
            sOpCode[8] = "S_OPCODE_INVLIST";
            sOpCode[9] = "S_OPCODE_ITEMNAME";
            sOpCode[10] = "S_OPCODE_POISON";
            sOpCode[11] = "S_OPCODE_TELEPORT";
            sOpCode[12] = "S_OPCODE_SHOWSHOPSELLLIST";
            sOpCode[13] = "S_OPCODE_CHARVISUALUPDATE";
            sOpCode[14] = "S_OPCODE_USEMAP";
            sOpCode[15] = "S_OPCODE_CHANGEHEADING";
            sOpCode[17] = "S_OPCODE_BLESSOFEVA";
            sOpCode[18] = "S_OPCODE_SELECTLIST";
            sOpCode[19] = "S_OPCODE_OWNCHARSTATUS2";
            sOpCode[20] = "S_OPCODE_SKILLBRAVE";
            sOpCode[21] = "S_OPCODE_TRADEADDITEM";
            sOpCode[22] = "S_OPCODE_INVIS";
            sOpCode[24] = "S_OPCODE_SHOWRETRIEVELIST";
            sOpCode[25] = "S_OPCODE_ITEMAMOUNT ";
            sOpCode[25] += "S_OPCODE_ITEMSTATUS";
            sOpCode[26] = "S_OPCODE_WARTIME";
            sOpCode[27] = "S_OPCODE_CHARRESET";
            sOpCode[28] = "S_OPCODE_ADDSKILL";
            sOpCode[29] = "S_OPCODE_NEWCHARWRONG";
            sOpCode[31] = "S_OPCODE_WEATHER";
            sOpCode[32] = "S_OPCODE_CHARTITLE";
            sOpCode[33] = "S_OPCODE_ADDITEM";
            sOpCode[34] = "S_OPCODE_HPUPDATE";
            sOpCode[35] = "S_OPCODE_ATTACKPACKET";
            sOpCode[37] = "S_OPCODE_SHOWHTML";
            sOpCode[38] = "S_OPCODE_CHANGENAME";
            sOpCode[39] = "S_OPCODE_NEWMASTER";
            sOpCode[41] = "S_OPCODE_DISCONNECT";
            sOpCode[43] = "S_OPCODE_LIQUOR";
            sOpCode[44] = "S_OPCODE_RESURRECTION";
            sOpCode[45] = "S_OPCODE_PUTSOLDIER";
            sOpCode[46] = "S_OPCODE_SHOWSHOPBUYLIST";
            sOpCode[47] = "S_OPCODE_WHISPERCHAT";
            sOpCode[48] = "S_OPCODE_SKILLBUY";
            sOpCode[49] = "S_OPCODE_SKILLHASTE";
            sOpCode[50] = "S_OPCODE_NPCSHOUT";
            sOpCode[51] = "S_OPCODE_DEXUP";
            sOpCode[52] = "S_OPCODE_SPMR";
            sOpCode[53] = "S_OPCODE_TRADE";
            sOpCode[55] = "S_OPCODE_SERVERSTAT";
            sOpCode[56] = "S_OPCODE_NEWCHARPACK";
            sOpCode[57] = "S_OPCODE_DELSKILL";
            sOpCode[58] = "S_OPCODE_GAMETIME";
            sOpCode[59] = "S_OPCODE_OWNCHARSTATUS";
            sOpCode[95] = "S_OPCODE_EXP";
            sOpCode[60] = "S_OPCODE_DEPOSIT";
            sOpCode[61] = "S_OPCODE_SELECTTARGET";
            sOpCode[62] = "S_OPCODE_PACKETBOX ";
            sOpCode[62] += "S_OPCODE_ACTIVESPELLS ";
            sOpCode[62] += "S_OPCODE_SKILLICONGFX";
            sOpCode[63] = "S_OPCODE_LOGINRESULT";
            sOpCode[65] = "S_OPCODE_BLUEMESSAGE";
            sOpCode[66] = "S_OPCODE_COMMONNEWS";
            sOpCode[67] = "S_OPCODE_DRAWAL";
            sOpCode[68] = "S_OPCODE_HIRESOLDIER";
            sOpCode[69] = "S_OPCODE_EFFECTLOCATION";
            sOpCode[70] = "S_OPCODE_TRUETARGET";
            sOpCode[71] = "S_OPCODE_NORMALCHAT";
            sOpCode[72] = "S_OPCODE_HOUSELIST";
            sOpCode[73] = "S_OPCODE_MAPID ";
            sOpCode[73] += "S_OPCODE_UNDERWATER";
            sOpCode[75] = "S_OPCODE_DELETEINVENTORYITEM";
            sOpCode[80] = "S_OPCODE_CHARAMOUNT";
            sOpCode[81] = "S_OPCODE_PARALYSIS";
            sOpCode[82] = "S_OPCODE_ATTRIBUTE";
            sOpCode[83] = "S_OPCODE_SOUND";
            sOpCode[84] = "S_OPCODE_DETELECHAROK";
            sOpCode[85] = "S_OPCODE_TELEPORTLOCK";
            sOpCode[86] = "S_OPCODE_ABILITY";
            sOpCode[87] = "S_OPCODE_PINKNAME";
            sOpCode[89] = "S_OPCODE_SERVERVERSION";
            sOpCode[91] = "S_OPCODE_BOARDREAD";
            sOpCode[92] = "S_OPCODE_MPUPDATE";
            sOpCode[93] = "S_OPCODE_BOARD";
            sOpCode[94] = "S_OPCODE_WAR";
            sOpCode[96] = "S_OPCODE_OWNCHARATTRDEF";
            sOpCode[97] = "S_OPCODE_RESTART";
            sOpCode[98] = "S_OPCODE_SERVERMSG";
            sOpCode[99] = "S_OPCODE_IDENTIFYDESC";
            sOpCode[100] = "S_OPCODE_PINGTIME";
            sOpCode[101] = "S_OPCODE_SKILLSOUNDGFX";
            sOpCode[102] = "S_OPCODE_CHARLIST";
            sOpCode[103] = "S_OPCODE_BOOKMARKS";
            sOpCode[104] = "S_OPCODE_HPMETER";
            sOpCode[105] = "S_OPCODE_YES_NO";
            sOpCode[106] = "S_OPCODE_STRUP";
            sOpCode[107] = "S_OPCODE_ITEMCOLOR";
            sOpCode[110] = "S_OPCODE_CURSEBLIND";
            sOpCode[111] = "S_OPCODE_CASTLEMASTER";
            sOpCode[112] = "S_OPCODE_RANGESKILLS";
            sOpCode[113] = "S_OPCODE_HOUSEMAP";
            sOpCode[114] = "S_OPCODE_SKILLICONSHIELD";
            sOpCode[115] = "S_OPCODE_PRIVATESHOPLIST";
            sOpCode[116] = "S_OPCODE_UNKNOWN1";
            sOpCode[117] = "S_OPCODE_CHARLOCK";
            sOpCode[119] = "S_OPCODE_LAWFUL";
            sOpCode[120] = "S_OPCODE_TAXRATE";
            sOpCode[122] = "S_OPCODE_TRADESTATUS";
            sOpCode[123] = "S_OPCODE_INPUTAMOUNT";
            sOpCode[124] = "S_OPCODE_LIGHT";
            sOpCode[126] = "S_OPCODE_MOVEOBJECT";
            sOpCode[127] = "S_OPCODE_MAIL";
        }
    }
}
